 1.Kafka高级特性解析之消费者中消费组的概念
   
   consumer group是kafka提供的可扩展且具有容错性的消费者机制。
   三个特性：
   1).消费组有一个或多个消费者，消费者可以是一个进程，也可以是一个线程
   2).group.id是一个字符串，唯一标识一个消费组
   3).消费组订阅的主题每个分区只能分配给消费组一个消费者。
 
 2.消费者位移(consumer position)
   
   消费者在消费的过程中记录已消费的数据，即消费位移（offset）信息。
   每个消费组保存自己的位移信息，那么只需要简单的一个整数表示位置就够了；同时可以引⼊checkpoint机制定
期持久化。
 
 3.位移管理(offset management)
   
   1)自动VS手动
   Kafka默认定期自动提交位移( enable.auto.commit = true )，也手动提交位移。另外kafka会定期把group消
费情况保存起来，做成一个offset map，如下图所示：
   2).位移提交
   位移是提交到Kafka中的__consumer_offsets 主题。__consumer_offsets 中的消息保存了每个消费组某一时
刻提交的offset信息。
   [root@node1 __consumer_offsets-0]# kafka-console-consumer.sh --topic __consumer_offsets
--bootstrap-server linux121:9092 --formatter
"kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter" --
consumer.config /opt/kafka_2.12-1.0.2/config/consumer.properties --from-beginning |
head
[console-consumer-20058,tp_demo_01,0]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011013307,ExpirationTime 1640097413307]
[console-consumer-20058,tp_demo_01,1]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011013307,ExpirationTime 1640097413307]
[console-consumer-20058,tp_demo_01,2]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011013307,ExpirationTime 1640097413307]
[console-consumer-20058,tp_demo_01,0]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011018307,ExpirationTime 1640097418307]
[console-consumer-20058,tp_demo_01,1]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011018307,ExpirationTime 1640097418307]
[console-consumer-20058,tp_demo_01,2]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011018307,ExpirationTime 1640097418307]
[console-consumer-20058,tp_demo_01,0]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011023311,ExpirationTime 1640097423311]
[console-consumer-20058,tp_demo_01,1]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011023311,ExpirationTime 1640097423311]
[console-consumer-20058,tp_demo_01,2]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011023311,ExpirationTime 1640097423311]
[console-consumer-20058,tp_demo_01,0]::[OffsetMetadata[20,NO_METADATA],CommitTime 1640011028313,ExpirationTime 1640097428313]

   上图中，标出来的，表示消费组为test-consumer-group ，消费的主题为__consumer_offsets ，消费的分区
是1，偏移量为20。
   __consumers_offsets 主题配置了compact策略，使得它总是能够保存最新的位移信息，既控制了该topic总体
的日志容量，也能实现保存最新offset的目的。
   
 4.再谈再均衡
   
   1).什么是再均衡？
   再均衡（Rebalance）本质上是一种协议，规定了一个消费组中所有消费者如何达成⼀致来分配订阅主题的每个
分区。
   比如某个消费组有20个消费组，订阅了一个具有100个分区的主题。正常情况下，Kafka平均会为每个消费者分配
5 个分区。这个分配的过程就叫再均衡。
   2).什么时候再均衡？
   再均衡的触发条件：
   (1).组成员发生变更(新消费者加入消费组组、已有消费者主动离开或崩溃了)
   (2).订阅主题数发生变更。如果正则表达式进行订阅，则新建匹配正则表达式的主题触发再均衡。
   (3).订阅主题的分区数发生变更
   3).如何进行组内分区分配？
   三种分配策略：RangeAssignor和RoundRobinAssignor以及StickyAssignor。后面讲。
   4).谁来执行再均衡和消费组管理？
   Kafka提供了一个角色：Group Coordinator来执⾏对于消费组的管理。
   Group Coordinator——每个消费组分配一个消费组协调器用于组管理和位移管理。当消费组的第一个消费者启
动的时候，它会去和Kafka Broker确定谁是它们组的组协调器。之后该消费组内所有消费者和该组协调器协调通信。
   5).如何确定coordinator？
   两步：
   (1).确定消费组位移信息写入__consumers_offsets 的哪个分区。具体计算公式：
          __consumers_offsets partition# = Math.abs(groupId.hashCode() %
          groupMetadataTopicPartitionCount) 注意：groupMetadataTopicPartitionCount
		  由offsets.topic.num.partitions 指定，默认是50个分区。
   (2).该分区leader所在的broker就是组协调器。
   6).Rebalance Generation
   它表示Rebalance之后主题分区到消费组中消费者映射关系的一个版本，主要是用于保护消费组，隔离无效偏移
量提交的。如上一个版本的消费者无法提交位移到新版本的消费组中，因为映射关系变了，你消费的或许已经不是原
来的那个分区了。每次group进行Rebalance之后，Generation号都会加1，表示消费组和分区的映射关系到了一个新
版本，如下图所示： Generation1时group有3个成员，随后成员2退出组，消费组协调器触发Rebalance，消费组进
入Generation2，之后成员4加入，再次触发Rebalance，消费组进行Generation3.
  7).协议(protocol)
  kafka提供了5个协议来处理与消费组协调相关的问题：
  Heartbeat请求：consumer需要定期给组协调器发送心跳来表明自己还活着
  LeaveGroup请求：主动告诉组协调器我要离开消费组
  SyncGroup请求：消费组Leader把分配方案告诉组内所有成员
  JoinGroup请求：成员请求加入组
  DescribeGroup请求：显示组的所有信息，包括成员信息，协议名称，分配方案，订阅信息等。通常该请求
是给管理员使用
  组协调器在再均衡的时候主要用到了前面4种请求。  
  8).liveness
  消费者如何向消费组协调器证明自己还活着？ 通过定时向消费组协调器发送Heartbeat请求。如果超过了设定的
超时时间，那么协调器认为该消费者已经挂了。一旦协调器认为某个消费者挂了，那么它就会开启新一轮再均衡，并
且在当前其他消费者的心跳响应中添加“REBALANCE_IN_PROGRESS”，告诉其他消费者：重新分配分区。
  9).再均衡过程
  再均衡分为2步：Join和Sync
  (1).Join， 加入组。所有成员都向消费组协调器发送JoinGroup请求，请求加入消费组。一旦所有成员都发送了
JoinGroup请求，协调i器从中选择一个消费者担任Leader的角色，并把组成员信息以及订阅信息发给Leader。
  (2).Sync，Leader开始分配消费方案，即哪个消费者负责消费哪些主题的哪些分区。一旦完成分配，Leader会将
这个方案封装进SyncGroup请求中发给消费组协调器，非Leader也会发SyncGroup请求，只是内容为空。消费组协调
器接收到分配方案之后会把方案塞进SyncGroup的response中发给各个消费者。
   注意：在协调器收集到所有成员请求前，它会把已收到请求放入一个叫purgatory(炼狱)的地方。然后是分发分配
方案的过程，即SyncGroup请求：
   注意：消费组的分区分配方案在客户端执行。Kafka交给客户端可以有更好的灵活性。Kafka默认提供三种分配策
略：range和round-robin和sticky。可以通过消费者的参数： partition.assignment.strategy 来实现自己分配策
略。 
   10).消费组状态机
   消费组组协调器根据状态机对消费组做不同的处理：
   说明：
   (1).Dead：组内已经没有任何成员的最终状态，组的元数据也已经被组协调器移除了。这种状态响应各种请求都
是一个response： UNKNOWN_MEMBER_ID
   (2).Empty：组内无成员，但是位移信息还没有过期。这种状态只能响应JoinGroup请求
   (3).PreparingRebalance：组准备开启新的rebalance，等待成员加入
   (4).AwaitingSync：正在等待leader consumer将分配方案传给各个成员
   (5).Stable：再均衡完成，可以开始消费。
   